图1 摘自《解构领域驱动设计》(张逸,2021)书中“状态和事件本质上是相同的”的观点真是令我“耳目一新”。那就针对这页书的内容来讲讲吧。我先介绍状态机的一些知识点,然后根据这些知识点来评价一下这页书中的内容。一、状态是描述某个类的“形容词”状态的名称和类的名称凑到一起,“状态的类”或“这个类是状态的”要能说得通。(也可以把整个系统当成一个类来描述状态,这时得到的状态机相当于系统的需求规约,这样的状态机往往是非常庞大的。)例如,针对“人”这个类,描述它的形容词可以有:高、矮、胖、瘦、贫、富、美、丑……等。“高的人”、“美的人”、“这个人是高的”、“这个人是美的”是可以说得通的,这些都可以作为“人”的状态。有的“形容词”是动词变化而来的,例如,“健身”是动词,但“正在健身的”、“已健身的”就变成了形容词,“正在健身的人”可以说得通。我们看英文书籍中的状态机图,往往可以看到很多名称中带有“ing”、“ed”的状态,就是现在分词、过去分词作为形容词使用。“domain-driven”就属于这种情况,说domain-driven(定语)design或说this design is domain-driven(表语)是可以的。图2是状态图。节点是状态,形容词;边是事件/动作,动词。
图7 摘自ActionInventory for a Knowledge-Based Colloquium Agent(ErikSandewall, 1999)当然,DDD圈子可以自行定义这个词。图8是Martin Fowler的定义:
图8 摘自https://martinfowler.com/eaaDev/DomainEvent.html从Fowler的陈述和所给类图可以知道,领域事件实际上就是一个“行为记录”类,像录像机一样,把发生过的事情的一些细节记下来。就是这么一个东西,没有必要过度渲染,活生生搞成玄学。Fowler加了一个限定“affects the domain”,也就是说,不是什么都记,影响领域的才记。“影响领域”是一个模糊的说法,后面Fowler又补充得更精确一些:“can trigger a change to thestate of the application(可以触发应用的状态变化)”。我把Fowler给出的类图翻成中文,如图9:
图12 摘自“Java Modeling in Color with UML:Enterprise Components and Process”(Peter Coad等,1999)(中文译名:彩色UML建模)事件风暴(我重点批评的伪创新之一)的“发明”者,Alberto Brandolini在他的书中说:
图13 摘自 Introducing EventStorming(Alberto Brandolini,2018)从Brandolini的陈述可知,他也认为领域事件用动词的过去式命名,另外他还提到“Domain Events as state transitions(领域事件作为状态迁移)”。显然也是搞混了“概念B(事件记录)”和“概念A(事件)”。触发迁移的是“概念A(事件)”不是“概念B(事件记录)”。(3)张逸搞混了“过去式”和“过去分词”。搞混“概念B(事件记录)”和“概念A(事件)”,Young、Brandolini和张逸都有。搞混“概念C(状态)”和“概念A(事件)”的,说“状态和事件本质是相同的”,“状态就是领域事件”的,却是张逸独一份。Fowler只是说领域事件可以触发状态的变化,Brandolini也只是说“领域事件作为状态迁移”。为什么张逸会把“概念C(状态)”和“概念A(事件)”搞混呢?原因可能是张逸搞混了“过去式”和“过去分词”(完成态),以致搞混了事件和状态。DDD话语体系中领域事件的命名是动词的过去式(前面已经说过,这实际上是不合适的)。动词的过去式还是动词,说的是瞬间的行为,不是形容词,不能用来做定语或表语,不能作为状态的名称。可以作为状态名称的是动词的过去分词。英语中,规则动词的过去式和过去分词后面都是ed,也许正是这一点让张逸误认为这两个ed是一回事,从而得出结论“状态就是领域事件”。碰到不规则动词,这个问题就暴露出来了。do的过去式是did,不能作为形容词,可以作为形容词使用的是“to do”、“doing”、“done”,这也是我们常见到的状态的名称。did是一个行为,瞬间发生就结束,done是一个状态,可以停留在那里很久。图14是滕云 译、张逸审的《实现领域驱动设计》中译本和原文对照,可以看到,其中把“paste tense”误译为“过去分词”,说明译者以及审校者在这个知识点是混淆的。